#include "processor.hpp"

extern std::map<uint64_t, Semaphore<std::array<char, 4096>>> memory;
static std::thread *threads[3];
CoreBus cbus;

Processor::Processor(size_t count, IOMessage *io)
{
	this->count = count;
	cores = new CalcCore[count];
	mems = new MemCore[count];
	pages = new TLB[count];
	bus = new MessageBus[count];
	message = new Semaphore<MESIMeta>;
	message->get() = {I, -1};
	this->io = io;
	for (int i = 0; i < count; i++)
	{
		memset(bus[i].sregs, 0, sizeof(uint64_t) * 16);
		cores[i] = CalcCore(bus + i, &cbus, i);
		mems[i] = MemCore(bus + i, message);
		pages[i] = TLB(bus + i);
	}
}
void Processor::boot()
{
	for (int i = 0; i < count; i++)
	{
		if (i == 0)
			bus[i].sregs[Status][0] = bus[i].sregs[Status][1] = Zero | Priv | Master;
		else
			bus[i].sregs[Status][0] = bus[i].sregs[Status][1] = Zero | Priv | Slave;
		bus[i].dMAR.unlock();
		bus[i].fresh = false;
		bus[i].priv = true;
		bus[i].size = 0;
		bus[i].access = 0;
		bus[i].MAR = 0;
		bus[i].MDR = 0;
	}
	for (int i = 0; i < 3; i++)
		threads[i] = new std::thread[count];
	for (int i = 0; i < count; i++)
	{
		threads[0][i] = std::thread(&CalcCore::run, &cores[i]);
		threads[1][i] = std::thread(&MemCore::run, &mems[i]);
		threads[2][i] = std::thread(&TLB::run, &pages[i]);
	}
	for (int i = 0; i < count; i++)
	{
		threads[0][i].detach();
		threads[1][i].detach();
		threads[2][i].detach();
	}
}
void Processor::run()
{
	while (true)
	{
		for (int i = 0; i < count; i++)
		{
			if (bus[i].needLoad.try_lock())
			// 需要上层介入的IO操作
			{ // 进入时上一次IO已完成
				bus[i].needLoad.lock();
				if (bus[i].size == 0xffff)
				{
					io->label = SHUTDOWN;
					io->start.unlock();
					return; // 关机
				}
				io->addr = bus[i].MDR;
				io->port = (bus[i].MAR & 0x1fffe) >> 1;
				if (bus[i].access & R) // 读取操作
					io->label = INPUT;
				else if (bus[i].access & W) // 写入操作
					io->label = (bus[i].MAR & 1 ? DATA : CONTROL) | OUTPUT;
				if (bus[i].MAR & 1)
					io->label |= DATA;
				else
					io->label |= CONTROL;
				io->id.w_lock();
				io->id.get() = {i, 0};
				io->id.w_unlock();
				io->start.unlock();
				io->end.lock(); // 等待当前IO完成
				if (io->label & INPUT)
					bus[i].MDR = io->addr;
				bus[i].done.unlock();
			}
		}
	}
}